package com.lzh.chatnote.chat.service.strategy;

import cn.hutool.core.bean.BeanUtil;
import com.lzh.chatnote.chat.dao.MessageDao;
import com.lzh.chatnote.chat.domain.entity.Message;
import com.lzh.chatnote.chat.domain.enums.MessageTypeEnum;
import com.lzh.chatnote.chat.domain.vo.request.message.MessageSendReq;
import com.lzh.chatnote.chat.service.adapter.MessageAdapter;
import com.lzh.chatnote.common.utils.AssertUtil;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 抽象类
 *
 * @param <REQ>
 */
public abstract class AbstractMsgHandler<REQ> {

    @Resource
    private MessageDao messageDao;

    private Class<REQ> reqClass;

    @PostConstruct
    public void init() {
        //获取泛型类型
        ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
        //获取泛型参数
        Type outType = genericSuperclass.getActualTypeArguments()[0];
        // 处理嵌套泛型类型
        if (outType instanceof Class) {
            // 普通类型
            this.reqClass = (Class<REQ>) outType;
        } else if (outType instanceof ParameterizedType) {
            // 嵌套泛型类型，获取原始类型
            this.reqClass = (Class<REQ>) ((ParameterizedType) outType).getRawType();
        } else {
            throw new IllegalArgumentException("Unsupported type: " + outType);
        }
        //注册到工厂里
        MsgFactoryHandler.register(getMessageTypeEnum().getType(), this);
    }

    //保留由子类实现
    protected abstract MessageTypeEnum getMessageTypeEnum();

    //扩展子类校验
    protected void checkReqArg(REQ req, Long uuid, Long roomId) {
    }
    //扩展子类保存消息操作
    protected abstract void saveMessage(Message message,REQ reqBean);

    //扩展子类实现返回响应体（不同的消息对于不同的响应对象）（具体什么对象由子类自己去实现）
    public abstract Object showMsgJsonObj(Message message);

    //扩展子类实现返回回复消息体（不同的消息对于不同的响应对象）（具体什么对象由子类自己去实现）
    public abstract Object showReplyMsgJsonObj(Message message);

    //检验消息参数，保存消息数据
    @Transactional(rollbackFor = Exception.class)
    public Long checkAndSaveMsg(MessageSendReq req, Long uuid) {
        //校验消息参数
        REQ reqBean = this.getBean(req);
        AssertUtil.allCheckValidateThrow(reqBean);
        //扩展子类校验
        checkReqArg(reqBean, uuid, req.getRoomId());
        //保存消息信息
        Message message = MessageAdapter.buildSendMsg(req, uuid);
        messageDao.save( message);
        //扩展子类保存消息
        saveMessage(message,reqBean);
        //返回
        return message.getId();
    }

    private REQ getBean(MessageSendReq req) {
        if (reqClass.isAssignableFrom(req.getMessage().getClass())) {
            return (REQ) req.getMessage();
        }
        return BeanUtil.toBean(req.getMessage(), reqClass);
    }


}
